home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / cpu / m6502 / m4510.c < prev    next >
C/C++ Source or Header  |  2000-05-08  |  14KB  |  524 lines

  1. /*****************************************************************************
  2.  *
  3.  *     m4510.c
  4.  *     Portable 4510 emulator V1.0beta1
  5.  *
  6.  *     Copyright (c) 2000 Peter Trauner, all rights reserved
  7.  *   documentation preliminary databook
  8.  *     documentation by michael steil mist@c64.org
  9.  *     available at ftp://ftp.funet.fi/pub/cbm/c65
  10.  *
  11.  *     - This source code is released as freeware for non-commercial purposes.
  12.  *     - You are free to use and redistribute this code in modified or
  13.  *       unmodified form, provided you list me in the credits.
  14.  *     - If you modify this source code, you must add a notice to each modified
  15.  *       source file that it has been changed.  If you're a nice person, you
  16.  *       will clearly mark each change too.  :)
  17.  *     - If you wish to use this for commercial purposes, please contact me at
  18.  *       pullmoll@t-online.de
  19.  *     - The author of this copywritten work reserves the right to change the
  20.  *       terms of its usage and license at any time, including retroactively
  21.  *     - This entire notice must remain in the source code.
  22.  *
  23.  *****************************************************************************/
  24.  
  25. /* 
  26.    c65 memory management
  27.    (reset)
  28.    c64 ff
  29.    c65 20 (interface)
  30.  
  31. a   (c65 mode)
  32.    a:00 x:e3 y:00 z:b3
  33.    c65 64 (interface)
  34.    c64 ff
  35.  
  36. b   (c65 dosmode?)
  37.    c65 65 (interface, full colorram)
  38.    a:00 x:11 y:80 z:31
  39.    c64 ff
  40.    
  41. c   (?)
  42.    c64 07
  43.    a:00 x:00 y:00 z:00
  44.  
  45.    a c65 mode
  46.  
  47.    diskcontroller accesses
  48.  
  49.  
  50.    monitor
  51.    c64 ff
  52.    a:a0 x:82 y:00 z:83
  53.  
  54.    c64 mode
  55.    c65 0
  56.    c65 2f:0 !
  57.    c64 ff
  58.    a:00 x:00 y:00 z:00
  59.    
  60. internal 8 mb to 64k switching (jmp routine in rom)
  61. ( seams to be incomplete, in chapter 1 1megabyte memory mapper )
  62.          a  x  y  z
  63. g      0 00 e0 00 f0
  64. g  10000 00 e1 00 f1
  65. g  20000 00 e2 00 f2
  66. g  30000 00 e3 00 f3
  67. g  40000 00 e4 00 f4
  68. g  50000 00 e5 00 f5
  69. g  60000 00 e6 00 f6
  70. .
  71. .
  72. g  f0000 00 ef 00 ff
  73. the same for 100000 .. 700000
  74. g 800000 00 e3 00 b3
  75.  
  76. thesis:
  77. a: ?0?0 0000
  78.    ? ?       only in monitor mode set
  79. x:      xxxx address bits a19 .. a16 for memory accesses with a15 0 ?
  80.    0000      c64 mode
  81.    0001      dosmode
  82.    1110      c65 mode, plain ram access 
  83.              (0000-1fff contains the switching code, so not switchable!?)
  84.    1000      monitor
  85.    1         map 6000-7fff
  86.     1        map 4000-5fff
  87.      1       map 2000-3fff
  88.       1      map 0000-1fff
  89. y: ?000 0000
  90.    ?         only in dos mode set
  91. z:      xxxx address bits a19 .. a16 for memory accesses with a15 1 ?
  92.    0000      c64 mode
  93.    0011      dosmode
  94.    1000      monitor
  95.    1011      c65 mode
  96.    1111      plain ram access
  97.    1         map e000-ffff
  98.     1        map c000-dfff
  99.      1       map a000-bfff
  100.       1      map 8000-9fff
  101.  */
  102.  
  103. #include <stdio.h>
  104. #include "driver.h"
  105. #include "state.h"
  106. #include "mamedbg.h"
  107. #include "m4510.h"
  108.  
  109. #include "ops02.h"
  110. #include "opsc02.h"
  111. #include "opsce02.h"
  112. #include "ops4510.h"
  113.  
  114. #define VERBOSE 0
  115.  
  116. #if VERBOSE
  117. #define LOG(x)    logerror x
  118. #else
  119. #define LOG(x)
  120. #endif
  121.  
  122. /* Layout of the registers in the debugger */
  123. static UINT8 m4510_reg_layout[] = {
  124.     M4510_A,M4510_X,M4510_Y,M4510_Z,M4510_S,M4510_PC,
  125.     M4510_MEM_LOW, 
  126.     -1,
  127.     M4510_EA,M4510_ZP,M4510_NMI_STATE,M4510_IRQ_STATE, M4510_B,
  128.     M4510_P, 
  129.     M4510_MEM_HIGH,
  130.     0
  131. };
  132.  
  133. /* Layout of the debugger windows x,y,w,h */
  134. static UINT8 m4510_win_layout[] = {
  135.     25, 0,55, 2,    /* register window (top, right rows) */
  136.      0, 0,24,22,    /* disassembler window (left colums) */
  137.     25, 3,55, 9,    /* memory #1 window (right, upper middle) */
  138.     25,13,55, 9,    /* memory #2 window (right, lower middle) */
  139.      0,23,80, 1,    /* command line window (bottom rows) */
  140. };
  141.  
  142. typedef struct {
  143.     void    (**insn)(void); /* pointer to the function pointer table */
  144.     PAIR    ppc;            /* previous program counter */
  145.     PAIR    pc;             /* program counter */
  146.     PAIR    sp;             /* stack pointer (always 100 - 1FF) */
  147.     PAIR    zp;             /* zero page address */
  148.     /* contains B register zp.b.h */
  149.     PAIR    ea;             /* effective address */
  150.     UINT8    a;                /* Accumulator */
  151.     UINT8    x;                /* X index register */
  152.     UINT8    y;                /* Y index register */
  153.     UINT8    z;                /* Z index register */
  154.     UINT8    p;                /* Processor status */
  155.     UINT8    pending_irq;    /* nonzero if an IRQ is pending */
  156.     UINT8    after_cli;        /* pending IRQ and last insn cleared I */
  157.     UINT8    nmi_state;
  158.     UINT8    irq_state;
  159.     UINT16  low, high;
  160.     UINT32    mem[8];    
  161.     int     (*irq_callback)(int irqline);    /* IRQ callback */
  162. }    m4510_Regs;
  163.  
  164. int m4510_ICount = 0;
  165.  
  166. static m4510_Regs m4510;
  167.  
  168. /***************************************************************
  169.  * include the opcode macros, functions and tables
  170.  ***************************************************************/
  171.  
  172. #define M4510
  173. #include "t65ce02.c"
  174.  
  175. void m4510_reset (void *param)
  176. {
  177.     m4510.insn = insn4510;
  178.  
  179.     /* wipe out the rest of the m65ce02 structure */
  180.     /* read the reset vector into PC */
  181.     /* reset z index and b bank */
  182.     PCL = RDMEM(M4510_RST_VEC);
  183.     PCH = RDMEM(M4510_RST_VEC+1);
  184.  
  185.     /* after reset in 6502 compatibility mode */
  186.     m4510.sp.d = 0x01ff; /* high byte descriped in databook */
  187.     m4510.z = 0;
  188.     B = 0;
  189.     m4510.p = F_E|F_B|F_I|F_Z;    /* set E, I and Z flags */
  190.     m4510.pending_irq = 0;    /* nonzero if an IRQ is pending */
  191.     m4510.after_cli = 0;        /* pending IRQ and last insn cleared I */
  192.     m4510.irq_callback = NULL;
  193.  
  194.     /* don't know */
  195.     m4510.high=0x8200;
  196.     m4510.mem[7]=0x20000;
  197.  
  198.     CHANGE_PC;
  199. }
  200.  
  201. void m4510_exit(void)
  202. {
  203.     /* nothing to do yet */
  204. }
  205.  
  206. unsigned m4510_get_context (void *dst)
  207. {
  208.     if( dst )
  209.         *(m4510_Regs*)dst = m4510;
  210.     return sizeof(m4510_Regs);
  211. }
  212.  
  213. void m4510_set_context (void *src)
  214. {
  215.     if( src )
  216.     {
  217.         m4510 = *(m4510_Regs*)src;
  218.         CHANGE_PC;
  219.     }
  220. }
  221.  
  222. unsigned m4510_get_pc (void)
  223. {
  224.     return M4510_MEM(PCD);
  225. }
  226.  
  227. void m4510_set_pc (unsigned val)
  228. {
  229.     PCW = val;
  230.     CHANGE_PC;
  231. }
  232.  
  233. unsigned m4510_get_sp (void)
  234. {
  235.     return S;
  236. }
  237.  
  238. void m4510_set_sp (unsigned val)
  239. {
  240.     S = val;
  241. }
  242.  
  243. unsigned m4510_get_reg (int regnum)
  244. {
  245.     switch( regnum )
  246.     {
  247.         case M4510_PC: return m4510.pc.w.l;
  248.         case M4510_S: return m4510.sp.w.l;
  249.         case M4510_P: return m4510.p;
  250.         case M4510_A: return m4510.a;
  251.         case M4510_X: return m4510.x;
  252.         case M4510_Y: return m4510.y;
  253.         case M4510_Z: return m4510.z;
  254.         case M4510_B: return m4510.zp.b.h;
  255.         case M4510_MEM_LOW: return m4510.low;
  256.         case M4510_MEM_HIGH: return m4510.high;
  257.         case M4510_MEM0: return m4510.mem[0];
  258.         case M4510_MEM1: return m4510.mem[1];
  259.         case M4510_MEM2: return m4510.mem[2];
  260.         case M4510_MEM3: return m4510.mem[3];
  261.         case M4510_MEM4: return m4510.mem[4];
  262.         case M4510_MEM5: return m4510.mem[5];
  263.         case M4510_MEM6: return m4510.mem[6];
  264.         case M4510_MEM7: return m4510.mem[7];
  265.         case M4510_EA: return m4510.ea.w.l;
  266.         case M4510_ZP: return m4510.zp.b.l;
  267.         case M4510_NMI_STATE: return m4510.nmi_state;
  268.         case M4510_IRQ_STATE: return m4510.irq_state;
  269.         case REG_PREVIOUSPC: return m4510.ppc.w.l;
  270.         default:
  271.             if( regnum <= REG_SP_CONTENTS )
  272.             {
  273.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  274.                 if( offset < 0x1ff )
  275.                     return RDMEM( offset ) | ( RDMEM( offset + 1 ) << 8 );
  276.             }
  277.     }
  278.     return 0;
  279. }
  280.  
  281. void m4510_set_reg (int regnum, unsigned val)
  282. {
  283.     switch( regnum )
  284.     {
  285.         case M4510_PC: m4510.pc.w.l = val; break;
  286.         case M4510_S: m4510.sp.w.l = val; break;
  287.         case M4510_P: m4510.p = val; break;
  288.         case M4510_MEM_LOW: 
  289.             m4510.low = val;
  290.             // change the memory registers
  291.             break;
  292.         case M4510_MEM_HIGH: 
  293.             m4510.high = val;
  294.             // change the memory registers
  295.             break;
  296.         case M4510_A: m4510.a = val; break;
  297.         case M4510_X: m4510.x = val; break;
  298.         case M4510_Y: m4510.y = val; break;
  299.         case M4510_Z: m4510.z = val; break;
  300.         case M4510_B: m4510.zp.b.h = val; break;
  301.         case M4510_EA: m4510.ea.w.l = val; break;
  302.         case M4510_ZP: m4510.zp.b.l = val; break;
  303.         case M4510_NMI_STATE: m4510_set_nmi_line( val ); break;
  304.         case M4510_IRQ_STATE: m4510_set_irq_line( 0, val ); break;
  305.         default:
  306.             if( regnum <= REG_SP_CONTENTS )
  307.             {
  308.                 unsigned offset = S + 2 * (REG_SP_CONTENTS - regnum);
  309.                 if( offset < 0x1ff )
  310.                 {
  311.                     WRMEM( offset, val & 0xfff );
  312.                     WRMEM( offset + 1, (val >> 8) & 0xff );
  313.                 }
  314.             }
  315.     }
  316. }
  317.  
  318. INLINE void m4510_take_irq(void)
  319. {
  320.     if( !(P & F_I) )
  321.     {
  322.         EAD = M4510_IRQ_VEC;
  323.         m4510_ICount -= 7;
  324.         PUSH(PCH);
  325.         PUSH(PCL);
  326.         PUSH(P & ~F_B);
  327.         P = (P & ~F_D) | F_I;        /* knock out D and set I flag */
  328.         PCL = RDMEM(EAD);
  329.         PCH = RDMEM(EAD+1);
  330.         LOG((errorlog,"M4510#%d takes IRQ ($%04x)\n", cpu_getactivecpu(), PCD));
  331.         /* call back the cpuintrf to let it clear the line */
  332.         if (m4510.irq_callback) (*m4510.irq_callback)(0);
  333.         CHANGE_PC;
  334.     }
  335.     m4510.pending_irq = 0;
  336. }
  337.  
  338. int m4510_execute(int cycles)
  339. {
  340.     m4510_ICount = cycles;
  341.  
  342.     CHANGE_PC;
  343.  
  344.     do
  345.     {
  346.         UINT8 op;
  347.         PPC = PCD;
  348.  
  349.         CALL_MAME_DEBUG;
  350.  
  351.         /* if an irq is pending, take it now */
  352.         if( m4510.pending_irq )
  353.             m4510_take_irq();
  354.  
  355.         op = RDOP();
  356.         (*insn4510[op])();
  357.  
  358.         /* check if the I flag was just reset (interrupts enabled) */
  359.         if( m4510.after_cli )
  360.         {
  361.             LOG((errorlog,"M4510#%d after_cli was >0", cpu_getactivecpu()));
  362.             m4510.after_cli = 0;
  363.             if (m4510.irq_state != CLEAR_LINE)
  364.             {
  365.                 LOG((errorlog,": irq line is asserted: set pending IRQ\n"));
  366.                 m4510.pending_irq = 1;
  367.             }
  368.             else
  369.             {
  370.                 LOG((errorlog,": irq line is clear\n"));
  371.             }
  372.         }
  373.         else
  374.         if( m4510.pending_irq )
  375.             m4510_take_irq();
  376.  
  377.     } while (m4510_ICount > 0);
  378.  
  379.     return cycles - m4510_ICount;
  380. }
  381.  
  382. void m4510_set_nmi_line(int state)
  383. {
  384.     if (m4510.nmi_state == state) return;
  385.     m4510.nmi_state = state;
  386.     if( state != CLEAR_LINE )
  387.     {
  388.         LOG((errorlog, "M4510#%d set_nmi_line(ASSERT)\n", cpu_getactivecpu()));
  389.         EAD = M4510_NMI_VEC;
  390.         m4510_ICount -= 7;
  391.         PUSH(PCH);
  392.         PUSH(PCL);
  393.         PUSH(P & ~F_B);
  394.         P = (P & ~F_D) | F_I;        /* knock out D and set I flag */
  395.         PCL = RDMEM(EAD);
  396.         PCH = RDMEM(EAD+1);
  397.         LOG((errorlog,"M4510#%d takes NMI ($%04x)\n", cpu_getactivecpu(), PCD));
  398.         CHANGE_PC;
  399.     }
  400. }
  401.  
  402. void m4510_set_irq_line(int irqline, int state)
  403. {
  404.     m4510.irq_state = state;
  405.     if( state != CLEAR_LINE )
  406.     {
  407.         LOG((errorlog, "M4510#%d set_irq_line(ASSERT)\n", cpu_getactivecpu()));
  408.         m4510.pending_irq = 1;
  409.     }
  410. }
  411.  
  412. void m4510_set_irq_callback(int (*callback)(int))
  413. {
  414.     m4510.irq_callback = callback;
  415. }
  416.  
  417. void m4510_state_save(void *file)
  418. {
  419.     int cpu = cpu_getactivecpu();
  420.     /* insn is set at restore since it's a pointer */
  421.     state_save_UINT16(file,"m4510",cpu,"PC",&m4510.pc.w.l,2);
  422.     state_save_UINT16(file,"m4510",cpu,"SP",&m4510.sp.w.l,2);
  423.     state_save_UINT8(file,"m4510",cpu,"P",&m4510.p,1);
  424.     state_save_UINT8(file,"m4510",cpu,"A",&m4510.a,1);
  425.     state_save_UINT8(file,"m4510",cpu,"X",&m4510.x,1);
  426.     state_save_UINT8(file,"m4510",cpu,"Y",&m4510.y,1);
  427.     state_save_UINT8(file,"m4510",cpu,"Z",&m4510.z,1);
  428.     state_save_UINT8(file,"m4510",cpu,"B",&m4510.zp.b.h,1);
  429.     state_save_UINT8(file,"m4510",cpu,"PENDING",&m4510.pending_irq,1);
  430.     state_save_UINT8(file,"m4510",cpu,"AFTER_CLI",&m4510.after_cli,1);
  431.     state_save_UINT8(file,"m4510",cpu,"NMI_STATE",&m4510.nmi_state,1);
  432.     state_save_UINT8(file,"m4510",cpu,"IRQ_STATE",&m4510.irq_state,1);
  433.     state_save_UINT16(file,"m4510",cpu,"LO",&m4510.low,2);
  434.     state_save_UINT16(file,"m4510",cpu,"HI",&m4510.high,2);
  435. }
  436.  
  437. void m4510_state_load(void *file)
  438. {
  439.     int cpu = cpu_getactivecpu();
  440.     m4510.insn = insn4510;
  441.     state_load_UINT16(file,"m4510",cpu,"PC",&m4510.pc.w.l,2);
  442.     state_load_UINT16(file,"m4510",cpu,"SP",&m4510.sp.w.l,2);
  443.     state_load_UINT8(file,"m4510",cpu,"P",&m4510.p,1);
  444.     state_load_UINT8(file,"m4510",cpu,"A",&m4510.a,1);
  445.     state_load_UINT8(file,"m4510",cpu,"X",&m4510.x,1);
  446.     state_load_UINT8(file,"m4510",cpu,"Y",&m4510.y,1);
  447.     state_load_UINT8(file,"m4510",cpu,"Z",&m4510.z,1);
  448.     state_load_UINT8(file,"m4510",cpu,"B",&m4510.zp.b.h,1);
  449.     state_load_UINT8(file,"m4510",cpu,"PENDING",&m4510.pending_irq,1);
  450.     state_load_UINT8(file,"m4510",cpu,"AFTER_CLI",&m4510.after_cli,1);
  451.     state_load_UINT8(file,"m4510",cpu,"NMI_STATE",&m4510.nmi_state,1);
  452.     state_load_UINT8(file,"m4510",cpu,"IRQ_STATE",&m4510.irq_state,1);
  453.     state_load_UINT16(file,"m4510",cpu,"LO",&m4510.low,2);
  454.     state_load_UINT16(file,"m4510",cpu,"HI",&m4510.high,2);
  455. }
  456.  
  457. /****************************************************************************
  458.  * Return a formatted string for a register
  459.  ****************************************************************************/
  460. const char *m4510_info(void *context, int regnum)
  461. {
  462.     static char buffer[16][47+1];
  463.     static int which = 0;
  464.     m4510_Regs *r = context;
  465.  
  466.     which = ++which % 16;
  467.     buffer[which][0] = '\0';
  468.     if( !context )
  469.         r = &m4510;
  470.  
  471.     switch( regnum )
  472.     {
  473.         case CPU_INFO_REG+M4510_PC: sprintf(buffer[which], "PC:%04X", r->pc.w.l); break;
  474.         case CPU_INFO_REG+M4510_S: sprintf(buffer[which], "S:%04X", r->sp.w.l); break;
  475.         case CPU_INFO_REG+M4510_P: sprintf(buffer[which], "P:%02X", r->p); break;
  476.         case CPU_INFO_REG+M4510_MEM_LOW: sprintf(buffer[which], "LO:%04X", r->low); break;
  477.         case CPU_INFO_REG+M4510_MEM_HIGH: sprintf(buffer[which], "HI:%04X", r->high); break;
  478.         case CPU_INFO_REG+M4510_A: sprintf(buffer[which], "A:%02X", r->a); break;
  479.         case CPU_INFO_REG+M4510_X: sprintf(buffer[which], "X:%02X", r->x); break;
  480.         case CPU_INFO_REG+M4510_Y: sprintf(buffer[which], "Y:%02X", r->y); break;
  481.         case CPU_INFO_REG+M4510_Z: sprintf(buffer[which], "Z:%02X", r->z); break;
  482.         case CPU_INFO_REG+M4510_B: sprintf(buffer[which], "B:%02X", r->zp.b.h); break;
  483.         case CPU_INFO_REG+M4510_EA: sprintf(buffer[which], "EA:%04X", r->ea.w.l); break;
  484.         case CPU_INFO_REG+M4510_ZP: sprintf(buffer[which], "ZP:%04X", r->zp.w.l); break;
  485.         case CPU_INFO_REG+M4510_NMI_STATE: sprintf(buffer[which], "NMI:%X", r->nmi_state); break;
  486.         case CPU_INFO_REG+M4510_IRQ_STATE: sprintf(buffer[which], "IRQ:%X", r->irq_state); break;
  487.         case CPU_INFO_FLAGS:
  488.             sprintf(buffer[which], "%c%c%c%c%c%c%c%c",
  489.                 r->p & 0x80 ? 'N':'.',
  490.                 r->p & 0x40 ? 'V':'.',
  491.                 r->p & 0x20 ? 'E':'.',
  492.                 r->p & 0x10 ? 'B':'.',
  493.                 r->p & 0x08 ? 'D':'.',
  494.                 r->p & 0x04 ? 'I':'.',
  495.                 r->p & 0x02 ? 'Z':'.',
  496.                 r->p & 0x01 ? 'C':'.');
  497.             break;
  498.         case CPU_INFO_NAME: return "M4510";
  499.         case CPU_INFO_FAMILY: return "CBM Semiconductor Group CSG 65CE02";
  500.         case CPU_INFO_VERSION: return "1.0beta";
  501.         case CPU_INFO_CREDITS:
  502.             return "Copyright (c) 1998 Juergen Buchmueller\n"
  503.                 "Copyright (c) 2000 Peter Trauner\n"
  504.                 "all rights reserved.";
  505.         case CPU_INFO_FILE: return __FILE__;
  506.         case CPU_INFO_REG_LAYOUT: return (const char*)m4510_reg_layout;
  507.         case CPU_INFO_WIN_LAYOUT: return (const char*)m4510_win_layout;
  508.     }
  509.     return buffer[which];
  510. }
  511.  
  512. unsigned m4510_dasm(char *buffer, unsigned pc)
  513. {
  514. #ifdef MAME_DEBUG
  515.     return Dasm4510( buffer, pc );
  516. #else
  517.     sprintf( buffer, "$%02X", cpu_readop(pc) );
  518.     return 1;
  519. #endif
  520. }
  521.  
  522.  
  523.  
  524.